package com.ragdollcat.thirdaicodegenerate.ai;

import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.ragdollcat.thirdaicodegenerate.AiCodeGeneratorService;
import com.ragdollcat.thirdaicodegenerate.core.parse.CodeParserExecutor;
import com.ragdollcat.thirdaicodegenerate.core.saver.CodeFileSaverExecutor;
import com.ragdollcat.thirdaicodegenerate.exception.ErrorCode;
import com.ragdollcat.thirdaicodegenerate.exception.ThrowUtils;
import com.ragdollcat.thirdaicodegenerate.model.entity.App;
import com.ragdollcat.thirdaicodegenerate.core.message.AiResponseMessage;
import com.ragdollcat.thirdaicodegenerate.core.message.ToolExecutedMessage;
import com.ragdollcat.thirdaicodegenerate.core.message.ToolRequestMessage;
import com.ragdollcat.thirdaicodegenerate.service.AppService;
import dev.langchain4j.model.chat.response.ChatResponse;
import dev.langchain4j.service.TokenStream;
import dev.langchain4j.service.tool.ToolExecution;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;

import java.io.File;

/**
 * 调用AI 生成结果 + 保存
 */
@Component
@Slf4j
public class CodeFileFacade {

//    @Resource
//    private AiCodeGeneratorService aiCodeGeneratorService;

    @Resource
    private AiCodeGeneratorFactory aiCodeGeneratorFactory;

    @Resource
    private AppService appService;

//    public File callAiAndSave(String userText, String bizType) {
//        ThrowUtils.throwIf(StrUtil.isEmpty(bizType), ErrorCode.PARAMS_ERROR);
//        return switch (bizType) {
//            case "html" -> {
//                //根据用户输入的生成文本
//                HtmlCodeResult htmlCodeResult = aiCodeGeneratorService.generateHtmlCode(userText);
//                //保存
//                yield CodeFileSaver.saveHtmlCode(htmlCodeResult);
//                //保存
//            }
//            case "multi_file" -> {
//                MultiFileCodeResult multiFileCodeResult = aiCodeGeneratorService.generateMultiFileCode(userText);
//                yield CodeFileSaver.saveMutliFileCode(multiFileCodeResult);
//            }
//            default -> null;
//        };
//    }


    /**
     * 流式返回
     *
     * @param userText
     * @param bizType
     * @param appId
     * @return
     */
    public Flux<String> callAiAndSaveWithFlux(String userText, String bizType, Long appId, int version) {
        //首先根据appId，拿到对应的AiCodeGeneratorService代理实例，这里走了缓存
        AiCodeGeneratorService aiCodeGeneratorService = aiCodeGeneratorFactory.visitCache(appId, bizType);


        ThrowUtils.throwIf(StrUtil.isEmpty(bizType), ErrorCode.PARAMS_ERROR);
        Flux<String> result = null;
        //AI根据用户输入的生成文本
        switch (bizType) {
            case "html" -> result = aiCodeGeneratorService.generateHtmlCodeWithFlux(userText);
            case "multi_file" -> result = aiCodeGeneratorService.generateMultiFileCodeWithFlux(userText);
            //增加vue工程类型 返回值需要特殊处理，统一成flux的格式
            case "vue_project" ->{
                    result = handlerVueCodeGenerate(aiCodeGeneratorService.generateVueProjectCodeWithFlux(appId + "_" + version, userText));
            }
            default -> ThrowUtils.throwIf(true, ErrorCode.PARAMS_ERROR, "该种任务类型不支持！");
        }

        //保存
        StringBuilder stringBuilder = new StringBuilder();
        //每个元素发出时，保存到stringBuilder中
        //vue项目无需手动解析保存，靠工具去保存
        return result.doOnNext(stringBuilder::append).
                //正常完成时
                        doOnComplete(() -> {
                    String strResult = stringBuilder.toString();
                    //转化
                    Object executeResult = CodeParserExecutor.execute(bizType, strResult);
                    //保存
                    File file = CodeFileSaverExecutor.getCodeFile(executeResult, bizType, appId, version);
                    if (ObjUtil.isNotEmpty(file)){
                        log.info("文件已保存，任务类型：{}，文件路径：{}", bizType, file.getAbsolutePath());
                    }

                    //文件保存成功后，该appId对应的版本号要 + 1
                    App appUpd = new App();
                    appUpd.setId(appId);
                    appUpd.setVersion(version + 1);
                    appService.updateById(appUpd);
                    log.info("文件保存成功，当前appId:{},版本号:{}", appId, version);
                });
    }


    /**
     * 将 TokenStream 转换为 Flux<String>，并传递工具调用信息
     *
     * @param tokenStream TokenStream 对象
     * @return Flux<String> 流式响应
     */
    private Flux<String> handlerVueCodeGenerate(TokenStream tokenStream) {
        return Flux.create(sink -> {
            //处理 AI 响应消息
            tokenStream.onPartialResponse((String partialResponse) -> {
                        AiResponseMessage aiResponseMessage = new AiResponseMessage(partialResponse);
                        //sink.next(element) → 等同于发布者的 onNext，用于发射一个元素；
                        sink.next(JSONUtil.toJsonStr(aiResponseMessage));
                    })
                    //处理 工具调用消息
                    .onPartialToolExecutionRequest((index, toolExecutionRequest) -> {
                        ToolRequestMessage toolRequestMessage = new ToolRequestMessage(toolExecutionRequest);
                        sink.next(JSONUtil.toJsonStr(toolRequestMessage));
                    })
                    //处理 工具执行结果消息
                    .onToolExecuted((ToolExecution toolExecution) -> {
                        ToolExecutedMessage toolExecutedMessage = new ToolExecutedMessage(toolExecution);
                        sink.next(JSONUtil.toJsonStr(toolExecutedMessage));
                    })
                    .onCompleteResponse((ChatResponse response) -> {
//                        sink.complete() → 等同于 onComplete，用于标记流正常结束；
                        sink.complete();
                    })
                    .onError((Throwable error) -> {
                        error.printStackTrace();
                        //sink.error(throwable) → 等同于 onError，用于标记流因错误终止。
                        sink.error(error);
                    })
                    .start();
        });
    }


}
